﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Soft
{


    /// <summary>
    /// 时间单位
    /// </summary>
    [TypeConverter(typeof(StructObjectTypeConverter<TimeUnitItem>))]
    [Serializable]
    public struct TimeUnitItem : IComparable<TimeUnitItem>, IComparable, IEquatable<TimeUnitItem>, IEqualityComparer<TimeUnitItem>
    {
        public TimeUnitItem(TimeUnit unit)
        {
            this.mText = "";
            this.mLength = 1;
            this.mUnit = unit;
            this.getText();
        }

        public TimeUnitItem(TimeUnit unit, int length)
        {
            this.mText = "";
            this.mUnit = unit;
            this.mLength = ((length == 0) ? ((unit != TimeUnit.NotSet) ? 1 : 0) : length);
            this.format_This();
            this.getText();
        }

   
        [Description("Time unit")]
        public TimeUnit Unit
        {
            get
            {
                return this.mUnit;
            }
            set
            {
                if (this.mUnit != value)
                {
                    this.mUnit = value;
                    this.format_This();
                    this.getText();
                }
            }
        }


        [Description("Length of the unit")]
        public int Length
        {
            get
            {
                return this.mLength;
            }
            set
            {
                if (this.mLength != value)
                {
                    this.mLength = value;
                    this.format_This();
                    this.getText();
                }
            }
        }

     
        [Browsable(false)]
        public string Text
        {
            get
            {
                return this.mText ?? string.Empty;
            }
            set
            {
                value = value.Trim();
                if (string.Compare(this.mText, value, true) != 0)
                {
                    this.setThis(value);
                }
            }
        }

        private void format_This()
        {
            int num = this.mLength;
            switch (this.mUnit)
            {
                case TimeUnit.Second:
                    num = 59;
                    break;
                case TimeUnit.Minute:
                    num = 59;
                    break;
                case TimeUnit.Hour:
                    num = 23;
                    break;
                case TimeUnit.Day:
                    num = 31;
                    break;
                case TimeUnit.Week:
                    num = 5;
                    break;
                case TimeUnit.Month:
                    num = 12;
                    break;
                case TimeUnit.Quarter:
                    num = 4;
                    break;
                case TimeUnit.Year:
                    num = 100;
                    break;
                case TimeUnit.Era:
                    num = 99;
                    break;
            }
            if (this.mLength > num)
            {
                this.mLength = num;
            }
            if (this.mLength < -num)
            {
                this.mLength = -num;
            }
        }

        private void getText()
        {
            if (this.mUnit != TimeUnit.NotSet && this.mLength != 0)
            {
                this.mText = string.Format("{0}.{1}", this.mUnit, this.mLength);
                return;
            }
            this.mText = "";
        }

        public bool IsEmpty()
        {
            return this.mLength == 0 || this.mUnit == TimeUnit.NotSet;
        }

        public long GetValue()
        {
            long result = 0L;
            switch (this.mUnit)
            {
                case TimeUnit.Second:
                    result = (long)this.mLength;
                    break;
                case TimeUnit.Minute:
                    result = (long)this.mLength * 60L;
                    break;
                case TimeUnit.Hour:
                    result = (long)this.mLength * 3600L;
                    break;
                case TimeUnit.Day:
                    result = (long)this.mLength * 86400L;
                    break;
                case TimeUnit.Week:
                    result = (long)this.mLength * 604800L;
                    break;
                case TimeUnit.Month:
                    result = (long)this.mLength * 2592000L;
                    break;
                case TimeUnit.Quarter:
                    result = (long)this.mLength * 7776000L;
                    break;
                case TimeUnit.Year:
                    result = (long)this.mLength * 31536000L;
                    break;
                //case TimeUnit.Era:
                //    result = (long)this.mLength * (long)((ulong)-1141367296);
                //    break;
            }
            return result;
        }

        public TimeUnitItem Turn(int value)
        {
            if (value == 0)
            {
                return this;
            }
            value = (int)(this.mUnit + value);
            if (value > 9)
            {
                return new TimeUnitItem(TimeUnit.Era, this.Length);
            }
            if (value < 1)
            {
                return new TimeUnitItem(TimeUnit.Second, this.Length);
            }
            return new TimeUnitItem((TimeUnit)value, this.Length);
        }

        private void setThis(string value)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                this.mUnit = TimeUnit.NotSet;
                this.mLength = 0;
            }
            else if (ToolsClass.RegexTest("^[a-zA-Z]+(\\.\\-?\\d{1,5})?$", value))
            {
                string[] array = value.Split(new char[]
                {
                    '.'
                }, StringSplitOptions.RemoveEmptyEntries);
                this.mUnit = array[0].ConvertTo(TimeUnit.NotSet, true);
                if (array.Length > 1)
                {
                    this.mLength = (int)array[1].ConvertTo(0, true);
                    if (this.mLength == 0)
                    {
                        this.mLength = 1;
                    }
                }
                else
                {
                    this.mLength = 1;
                }
            }
            this.format_This();
            this.getText();
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (obj.GetType() != typeof(TimeUnitItem))
            {
                throw new ArgumentException("参数对象不是一个 " + typeof(TimeUnitItem).FullName + " 类型", "obj");
            }
            return this.Equals((TimeUnitItem)obj);
        }

        public override int GetHashCode()
        {
            return this.Unit.GetHashCode() ^ this.mLength.GetHashCode();
        }

        public override string ToString()
        {
            return this.mText;
        }

        public int CompareTo(TimeUnitItem other)
        {
            return this.GetValue().CompareTo(other.GetValue());
        }

        public int CompareTo(object obj)
        {
            if (obj == null)
            {
                throw new ArgumentNullException("obj");
            }
            if (obj.GetType() != typeof(TimeUnitItem))
            {
                throw new ArgumentException("参数对象不是一个 " + typeof(TimeUnitItem).FullName + " 类型", "obj");
            }
            return this.CompareTo((TimeUnitItem)obj);
        }

        public bool Equals(TimeUnitItem other)
        {
            return this.mUnit == other.mUnit && this.mLength == other.mLength;
        }

        public bool Equals(TimeUnitItem x, TimeUnitItem y)
        {
            return x.Unit == y.Unit && x.Length == y.Length;
        }

        public int GetHashCode(TimeUnitItem obj)
        {
            return obj.GetHashCode();
        }

        public static TimeUnitItem Parse(string value)
        {
            value = (value ?? string.Empty);
            return new TimeUnitItem
            {
                Text = value
            };
        }

        public static bool operator ==(TimeUnitItem a, TimeUnitItem b)
        {
            return a.Equals(b);
        }

        public static bool operator !=(TimeUnitItem a, TimeUnitItem b)
        {
            return !a.Equals(b);
        }

        public static explicit operator TimeUnitItem(string value)
        {
            return new TimeUnitItem
            {
                Text = value
            };
        }

        public static explicit operator string(TimeUnitItem item)
        {
            return item.Text;
        }

        public static explicit operator TimeUnitItem(TimeUnit value)
        {
            return new TimeUnitItem(value, 1);
        }

        private TimeUnit mUnit;

        private int mLength;

        private string mText;

        public static readonly TimeUnitItem Empty = new TimeUnitItem
        {
            mUnit = TimeUnit.NotSet,
            mLength = 0
        };

        public static readonly TimeUnitItem MinValue = new TimeUnitItem(TimeUnit.Second, 1);

        public static readonly TimeUnitItem MaxValue = new TimeUnitItem(TimeUnit.Era, 99);
    }
}
